﻿//
//  SBXCrossover.cs
//
//  Author:
//       Antonio J. Nebro <antonio@lcc.uma.es>
//
//  Copyright (c) 2011 Antonio J. Nebro
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using jmetal.core;
using jmetal.util;

namespace jmetal.operators.crossover
{
    public class SinglePointCrossover : Crossover
    {
        public const double ETA_C_DEFAULT_ = 20.0;

        // EPS defines the minimum difference allowed between real values
        private const double EPS = 1.0e-14;

        private static Type[] validTypes = new Type[] { System.Type.GetType("jmetal.encodings.solutionType.RealSolutionType"), System.Type.GetType("jmetal.encodings.solutionType.BinarySolutionType") };

        private double crossoverProbability_ = 0.0;
        private double distributionIndex_ = ETA_C_DEFAULT_;

        public SinglePointCrossover(Dictionary<string, object> parameters)
            : base(parameters)
        {
            // <pex>
            if (parameters == (Dictionary<string, object>)null)
                throw new ArgumentNullException("parameters");
            // </pex>
            if (parameters.ContainsKey("probability"))
                crossoverProbability_ = (double)parameters["probability"];

            if (parameters.ContainsKey("distributionIndex"))
                distributionIndex_ = (double)parameters["distributionIndex"];

            Console.WriteLine("SBX probability: " + crossoverProbability_);
            Console.WriteLine("SBX distributionIndex: " + distributionIndex_);
        }

        public override object execute(object obj)
        {
            Solution[] parents = (Solution[])obj;

            if ((Array.Find(validTypes, n => n == parents[0].type_.GetType()) == null) ||
                (Array.Find(validTypes, n => n == parents[1].type_.GetType()) == null))
                Console.WriteLine("SBX. Types are incompatible");
            else ;
            //Console.WriteLine ("SBX. Types are Compatible");

            Solution[] offspring;
            offspring = doCrossover(parents[0], parents[1]);

            return offspring;
        }

        Solution[] doCrossover(Solution parent1, Solution parent2)
        {
            Solution[] offSpring = new Solution[2];

            offSpring[0] = new Solution(parent1);
            offSpring[1] = new Solution(parent2);

            int i;
            double rand;
            double y1, y2, yL, yu;
            double c1, c2;
            double alpha, beta, betaq;
            double valueX1, valueX2;
            Solution x1 = parent1;
            Solution x2 = parent2;
            Solution offs1 = offSpring[0];
            Solution offs2 = offSpring[1];

            int numberOfVariables = x1.numberOfVariables_;

            if (PseudoRandom.Instance().NextDouble() <= crossoverProbability_)
            {
                int crossOverPOint = PseudoRandom.Instance().Next(numberOfVariables);
                double whichPart = PseudoRandom.Instance().NextDouble();

                if (whichPart < 0.5)
                {
                    for (i = 0; i < crossOverPOint; i++)
                    {
                        offs1.variable_[i].value_ = x1.variable_[i].value_;
                        offs2.variable_[i].value_ = x2.variable_[i].value_;
                    }

                    for (i = crossOverPOint; i < numberOfVariables; i++)
                    {
                        offs1.variable_[i].value_ = x2.variable_[i].value_;
                        offs2.variable_[i].value_ = x1.variable_[i].value_;
                    }
                }
                else
                {
                    for (i = crossOverPOint; i < numberOfVariables; i++)
                    {
                        offs1.variable_[i].value_ = x1.variable_[i].value_;
                        offs2.variable_[i].value_ = x2.variable_[i].value_;
                    }

                    for (i = 0; i < crossOverPOint; i++)
                    {
                        offs1.variable_[i].value_ = x2.variable_[i].value_;
                        offs2.variable_[i].value_ = x1.variable_[i].value_;
                    }
                }

                // if
            }
            // if
            return offSpring;
        }
    }

}
